home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-9.10-netbook-remix-PL.iso / casper / filesystem.squashfs / usr / share / system-config-printer / applet.py < prev    next >
Text File  |  2009-10-19  |  16KB  |  443 lines

  1. #!/usr/bin/env python
  2.  
  3. ## Copyright (C) 2007, 2008, 2009 Tim Waugh <twaugh@redhat.com>
  4. ## Copyright (C) 2007, 2008, 2009 Red Hat, Inc.
  5.  
  6. ## This program is free software; you can redistribute it and/or modify
  7. ## it under the terms of the GNU General Public License as published by
  8. ## the Free Software Foundation; either version 2 of the License, or
  9. ## (at your option) any later version.
  10.  
  11. ## This program is distributed in the hope that it will be useful,
  12. ## but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. ## GNU General Public License for more details.
  15.  
  16. ## You should have received a copy of the GNU General Public License
  17. ## along with this program; if not, write to the Free Software
  18. ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20. import cups
  21. cups.require ("1.9.42")
  22. import sys
  23. import statereason
  24. from statereason import StateReason
  25. from debug import *
  26. import pprint
  27.  
  28. import dbus
  29. import dbus.glib
  30. import dbus.service
  31. import gobject
  32. import pynotify
  33. import time
  34. import locale
  35. import gettext
  36. from gettext import gettext as _
  37. DOMAIN="system-config-printer"
  38. gettext.textdomain (DOMAIN)
  39. statereason.set_gettext_function (_)
  40. try:
  41.     locale.setlocale (locale.LC_ALL, "")
  42. except locale.Error, e:
  43.     import os
  44.     os.environ['LC_ALL'] = 'C'
  45.     locale.setlocale (locale.LC_ALL, "")
  46.  
  47. APPDIR="/usr/share/system-config-printer"
  48. DOMAIN="system-config-printer"
  49. ICON="printer"
  50. SEARCHING_ICON="document-print-preview"
  51.  
  52. # We need to call pynotify.init before we can check the server for caps
  53. pynotify.init('System Config Printer Notification')
  54.  
  55. ####
  56. #### NewPrinterNotification DBus server (the 'new' way).
  57. ####
  58. PDS_PATH="/com/redhat/NewPrinterNotification"
  59. PDS_IFACE="com.redhat.NewPrinterNotification"
  60. PDS_OBJ="com.redhat.NewPrinterNotification"
  61. class NewPrinterNotification(dbus.service.Object):
  62.     STATUS_SUCCESS = 0
  63.     STATUS_MODEL_MISMATCH = 1
  64.     STATUS_GENERIC_DRIVER = 2
  65.     STATUS_NO_DRIVER = 3
  66.  
  67.     def __init__ (self, bus):
  68.         self.bus = bus
  69.         self.getting_ready = 0
  70.         bus_name = dbus.service.BusName (PDS_OBJ, bus=bus)
  71.         dbus.service.Object.__init__ (self, bus_name, PDS_PATH)
  72.  
  73.     def wake_up (self):
  74.         global waitloop, runloop, viewer
  75.         import jobviewer
  76.         if viewer == None:
  77.             try:
  78.                 waitloop.quit ()
  79.             except:
  80.                 pass
  81.             runloop = gobject.MainLoop ()
  82.             viewer = jobviewer.JobViewer(bus=bus, loop=runloop,
  83.                                          service_running=service_running,
  84.                                          trayicon=trayicon,
  85.                                          suppress_icon_hide=True)
  86.  
  87.     @dbus.service.method(PDS_IFACE, in_signature='', out_signature='')
  88.     def GetReady (self):
  89.         self.wake_up ()
  90.         if self.getting_ready == 0:
  91.             viewer.set_special_statusicon (SEARCHING_ICON,
  92.                                            tooltip=_("Configuring new printer"))
  93.  
  94.         self.getting_ready += 1
  95.         gobject.timeout_add (60 * 1000, self.timeout_ready)
  96.  
  97.     def timeout_ready (self):
  98.         global viewer
  99.         if self.getting_ready > 0:
  100.             self.getting_ready -= 1
  101.         if self.getting_ready == 0:
  102.             viewer.unset_special_statusicon ()
  103.  
  104.         return False
  105.  
  106.     @dbus.service.method(PDS_IFACE, in_signature='isssss', out_signature='')
  107.     def NewPrinter (self, status, name, mfg, mdl, des, cmd):
  108.         global viewer
  109.         self.wake_up ()
  110.  
  111.         if name.find("/") >= 0:
  112.             # name is a URI, no queue was generated, because no suitable
  113.             # driver was found
  114.             title = _("Missing printer driver")
  115.             devid = "MFG:%s;MDL:%s;DES:%s;CMD:%s;" % (mfg, mdl, des, cmd)
  116.             if (mfg and mdl) or des:
  117.                 if (mfg and mdl):
  118.                     device = "%s %s" % (mfg, mdl)
  119.                 else:
  120.                     device = des
  121.                 text = _("No printer driver for %s.") % device
  122.             else:
  123.                 text = _("No driver for this printer.")
  124.             n = pynotify.Notification (title, text, 'printer')
  125.             if "actions" in pynotify.get_server_caps():
  126.                 n.set_urgency (pynotify.URGENCY_CRITICAL)
  127.                 n.add_action ("setup-printer", _("Search"),
  128.                               lambda x, y:
  129.                                   self.setup_printer (x, y, name, devid))
  130.             else:
  131.                 args = ["--setup-printer", name, "--devid", devid]
  132.                 self.run_config_tool (args)
  133.  
  134.         else:
  135.             # name is the name of the queue which hal_lpadmin has set up
  136.             # automatically.
  137.             c = cups.Connection ()
  138.             try:
  139.                 printer = c.getPrinters ()[name]
  140.             except KeyError:
  141.                 return
  142.  
  143.             try:
  144.                 filename = c.getPPD (name)
  145.             except cups.IPPError:
  146.                 return
  147.  
  148.             del c
  149.  
  150.             # Check for missing packages
  151.             try:
  152.                 cups.ppdSetConformance (cups.PPD_CONFORM_RELAXED)
  153.             except AttributeError:
  154.                 # Requires pycups 1.9.46
  155.                 pass
  156.  
  157.             ppd = cups.PPD (filename)
  158.             import os
  159.             os.unlink (filename)
  160.             import sys
  161.             sys.path.append (APPDIR)
  162.             import cupshelpers
  163.             (missing_pkgs,
  164.              missing_exes) = cupshelpers.missingPackagesAndExecutables (ppd)
  165.  
  166.             from cupshelpers.ppds import ppdMakeModelSplit
  167.             (make, model) = ppdMakeModelSplit (printer['printer-make-and-model'])
  168.             driver = make + " " + model
  169.             if status < self.STATUS_GENERIC_DRIVER:
  170.                 title = _("Printer added")
  171.             else:
  172.                 title = _("Missing printer driver")
  173.  
  174.             if len (missing_pkgs) > 0:
  175.                 pkgs = reduce (lambda x,y: x + ", " + y, missing_pkgs)
  176.                 title = _("Install printer driver")
  177.                 text = _("`%s' requires driver installation: %s.") % (name, pkgs)
  178.                 n = pynotify.Notification (title, text)
  179.                 import installpackage
  180.                 if "actions" in pynotify.get_server_caps():
  181.                     try:
  182.                         self.packagekit = installpackage.PackageKit ()
  183.                         n.add_action ("install-driver", _("Install"),
  184.                                       lambda x, y:
  185.                                           self.install_driver (x, y,
  186.                                                                missing_pkgs))
  187.                     except:
  188.                         pass
  189.                 else:
  190.                     try:
  191.                         self.packagekit = installpackage.PackageKit ()
  192.                         self.packagekit.InstallPackageName (0, 0,
  193.                                                             missing_pkgs[0])
  194.                     except:
  195.                         pass
  196.  
  197.             elif status == self.STATUS_SUCCESS:
  198.                 devid = "MFG:%s;MDL:%s;DES:%s;CMD:%s;" % (mfg, mdl, des, cmd)
  199.                 text = _("`%s' is ready for printing.") % name
  200.                 n = pynotify.Notification (title, text)
  201.                 if "actions" in pynotify.get_server_caps():
  202.                     n.set_urgency (pynotify.URGENCY_NORMAL)
  203.                     n.add_action ("test-page", _("Print test page"),
  204.                                   lambda x, y:
  205.                                       self.print_test_page (x, y, name, devid))
  206.                     n.add_action ("configure", _("Configure"),
  207.                                   lambda x, y: self.configure (x, y, name))
  208.             else: # Model mismatch
  209.                 devid = "MFG:%s;MDL:%s;DES:%s;CMD:%s;" % (mfg, mdl, des, cmd)
  210.                 text = (_("`%s' has been added, using the `%s' driver.") %
  211.                         (name, driver))
  212.                 n = pynotify.Notification (title, text, 'printer')
  213.                 if "actions" in pynotify.get_server_caps():
  214.                     n.set_urgency (pynotify.URGENCY_CRITICAL)
  215.                     n.add_action ("test-page", _("Print test page"),
  216.                                   lambda x, y:
  217.                                       self.print_test_page (x, y, name, devid))
  218.                     n.add_action ("find-driver", _("Find driver"),
  219.                                   lambda x, y: 
  220.                                   self.find_driver (x, y, name, devid))
  221.                     n.set_timeout (pynotify.EXPIRES_NEVER)
  222.                 else:
  223.                     self.run_config_tool (["--configure-printer",
  224.                                            name, "--no-focus-on-map"])
  225.  
  226.         viewer.notify_new_printer (name, n)
  227.         # Set the icon back how it was.
  228.         self.timeout_ready ()
  229.  
  230.     def run_config_tool (self, argv):
  231.         import os
  232.         pid = os.fork ()
  233.         if pid == 0:
  234.             # Child.
  235.             cmd = "/usr/bin/system-config-printer"
  236.             argv.insert (0, cmd)
  237.             os.execvp (cmd, argv)
  238.             sys.exit (1)
  239.         elif pid == -1:
  240.             print "Error forking process"
  241.         else:
  242.             gobject.timeout_add (60 * 1000, self.collect_exit_code, pid)
  243.  
  244.     def print_test_page (self, notification, action, name, devid = ""):
  245.         args = ["--print-test-page", name]
  246.         if devid != "":
  247.             args.extend (["--devid", devid])
  248.         self.run_config_tool (args)
  249.  
  250.     def configure (self, notification, action, name):
  251.         self.run_config_tool (["--configure-printer", name])
  252.  
  253.     def find_driver (self, notification, action, name, devid = ""):
  254.         args = ["--choose-driver", name]
  255.         if devid != "": args = args + ["--devid", devid]
  256.         self.run_config_tool (args)
  257.  
  258.     def setup_printer (self, notification, action, uri, devid = ""):
  259.         args = ["--setup-printer", uri]
  260.         if devid != "": args = args + ["--devid", devid]
  261.         self.run_config_tool (args)
  262.  
  263.     def install_driver (self, notification, action, missing_pkgs):
  264.         try:
  265.             self.packagekit.InstallPackageName (0, 0, missing_pkgs[0])
  266.         except:
  267.             pass
  268.  
  269.     def collect_exit_code (self, pid):
  270.         # We do this with timers instead of signals because we already
  271.         # have gobject imported, but don't (yet) import signal;
  272.         # let's try not to inflate the process size.
  273.         import os
  274.         try:
  275.             print "Waiting for child %d" % pid
  276.             (pid, status) = os.waitpid (pid, os.WNOHANG)
  277.             if pid == 0:
  278.                 # Run this timer again.
  279.                 return True
  280.         except OSError:
  281.             pass
  282.  
  283.         return False
  284.  
  285. PROGRAM_NAME="system-config-printer-applet"
  286. def show_help ():
  287.     print "usage: %s [--no-tray-icon]" % PROGRAM_NAME
  288.  
  289. def show_version ():
  290.     import config
  291.     print "%s %s" % (PROGRAM_NAME, config.VERSION)
  292.     
  293. ####
  294. #### Main program entry
  295. ####
  296.  
  297. global waitloop, runloop, viewer
  298.  
  299. trayicon = True
  300. service_running = False
  301. waitloop = runloop = None
  302. viewer = None
  303.  
  304. if __name__ == '__main__':
  305.     import sys, getopt
  306.     try:
  307.         opts, args = getopt.gnu_getopt (sys.argv[1:], '',
  308.                                         ['no-tray-icon',
  309.                                          'debug',
  310.                                          'help',
  311.                                          'version'])
  312.     except getopt.GetoptError:
  313.         show_help ()
  314.         sys.exit (1)
  315.  
  316.     for opt, optarg in opts:
  317.         if opt == "--help":
  318.             show_help ()
  319.             sys.exit (0)
  320.         if opt == "--version":
  321.             show_version ()
  322.             sys.exit (0)
  323.         if opt == "--no-tray-icon":
  324.             trayicon = False
  325.         elif opt == "--debug":
  326.             set_debugging (True)
  327.  
  328.     # Must be done before connecting to D-Bus (for some reason).
  329.     if not pynotify.init (PROGRAM_NAME):
  330.         try:
  331.             print >> sys.stderr, ("%s: unable to initialize pynotify" %
  332.                                   PROGRAM_NAME)
  333.         except:
  334.             pass
  335.  
  336.     if trayicon:
  337.         # Stop running when the session ends.
  338.         def monitor_session (*args):
  339.             pass
  340.  
  341.         try:
  342.             bus = dbus.SessionBus()
  343.             bus.add_signal_receiver (monitor_session)
  344.         except:
  345.             try:
  346.                 print >> sys.stderr, ("%s: failed to connect to "
  347.                                       "session D-Bus" % PROGRAM_NAME)
  348.             finally:
  349.                 sys.exit (1)
  350.  
  351.     try:
  352.         bus = dbus.SystemBus()
  353.     except:
  354.         try:
  355.             print >> sys.stderr, ("%s: failed to connect to system D-Bus" %
  356.                                   PROGRAM_NAME)
  357.         finally:
  358.             sys.exit (1)
  359.  
  360.     if trayicon:
  361.         try:
  362.             NewPrinterNotification(bus)
  363.             service_running = True
  364.         except:
  365.             try:
  366.                 print >> sys.stderr, ("%s: failed to start "
  367.                                       "NewPrinterNotification service" %
  368.                                       PROGRAM_NAME)
  369.             except:
  370.                 pass
  371.  
  372.     if trayicon and get_debugging () == False:
  373.         # Start off just waiting for print jobs.
  374.         def any_jobs ():
  375.             try:
  376.                 c = cups.Connection ()
  377.                 jobs = c.getJobs (my_jobs=True, limit=1)
  378.                 if len (jobs):
  379.                     return True
  380.             except:
  381.                 pass
  382.  
  383.             return False
  384.  
  385.         if not any_jobs ():
  386.  
  387.             ###
  388.             class WaitForJobs:
  389.                 DBUS_PATH="/com/redhat/PrinterSpooler"
  390.                 DBUS_IFACE="com.redhat.PrinterSpooler"
  391.  
  392.                 def __init__ (self, bus, waitloop):
  393.                     self.bus = bus
  394.                     self.waitloop = waitloop
  395.                     self.timer = None
  396.                     bus.add_signal_receiver (self.handle_dbus_signal,
  397.                                              path=self.DBUS_PATH,
  398.                                              dbus_interface=self.DBUS_IFACE)
  399.  
  400.                 def __del__ (self):
  401.                     bus = self.bus
  402.                     bus.remove_signal_receiver (self.handle_dbus_signal,
  403.                                                 path=self.DBUS_PATH,
  404.                                                 dbus_interface=self.DBUS_IFACE)
  405.                     if self.timer:
  406.                         gobject.source_remove (self.timer)
  407.  
  408.                 def handle_dbus_signal (self, *args):
  409.                     if self.timer:
  410.                         gobject.source_remove (self.timer)
  411.                     self.timer = gobject.timeout_add (200, self.check_for_jobs)
  412.  
  413.                 def check_for_jobs (self, *args):
  414.                     debugprint ("checking for jobs")
  415.                     if any_jobs ():
  416.                         gobject.source_remove (self.timer)
  417.                         self.waitloop.quit ()
  418.  
  419.                     # Don't run this timer again.
  420.                     return False
  421.             ###
  422.  
  423.             waitloop = gobject.MainLoop ()
  424.             jobwaiter = WaitForJobs(bus, waitloop)
  425.             waitloop.run()
  426.             del jobwaiter
  427.             waitloop = None
  428.  
  429.     if viewer == None:
  430.         import jobviewer
  431.         import gtk
  432.         runloop = gobject.MainLoop ()
  433.         gtk.window_set_default_icon_name ('printer')
  434.         viewer = jobviewer.JobViewer(bus=bus, loop=runloop,
  435.                                      service_running=service_running,
  436.                                      trayicon=trayicon)
  437.  
  438.     try:
  439.         runloop.run()
  440.     except KeyboardInterrupt:
  441.         pass
  442.     viewer.cleanup ()
  443.